package gsp420.helloworld;

/** a simple singly-linked Queue implementation */
public class LinkedList<TYPE> implements Runnable
{
	public class Node
	{
		TYPE data;
		Node next;
		Node(TYPE a_data){
			data = a_data;
			next = null;
		}
	}
	
	Node head;
	
	Node getLastNode(){
		Node cursor = head;
		while(cursor != null && cursor.next != null){
			cursor = cursor.next;
		}
		return cursor;
	}
	
	void enqueueNode(Node n)
	{
		if(head == null)
			head = n;
		else
			getLastNode().next = n;
	}

	void enqueue(TYPE data)
	{
		enqueueNode(new Node(data));
	}
	
	TYPE get(int index){
		Node cursor = head;
		int i = 0;
		while(cursor != null && i < index){
			++i;
			cursor = cursor.next;
		}
		if(cursor != null)
			return cursor.data;
		throw new IndexOutOfBoundsException();
	}
	
	Node dequeueNode(){
		Node first = head;
		if(head != null){
			head = head.next;
			first.next = null;
		}
		return first;
	}
	
	int size(){
		Node cursor = head;
		int i = 0;
		while(cursor != null){
			++i;
			cursor = cursor.next;
		}
		return i;
	}
	
	TYPE dequeue(){
		return dequeueNode().data;
	}
	
//	[1]->[10]->[35]->[48]->[50]->[12]->NULL
	
	volatile boolean isBeingUsed = false;
	void lock(){
		while(isBeingUsed){
			try{Thread.sleep(1);}catch(Exception e){}				
		}
		isBeingUsed = true;
	}
	void unlock(){
		isBeingUsed = false;		
	}
	
	void doTheTerribleThreadingThing(){
		int count = size();
		for(int i = 0; i < count; ++i){
//			lock();
			synchronized(this){
				TYPE value = dequeue();
				enqueue(value);
				try{Thread.sleep(1);}catch(Exception e){}
			}
//			unlock();
		}
	}
	
	public void run(){
		doTheTerribleThreadingThing();
	}
	
	void print(){
		System.out.print("{");
		for(int i = 0; i < size(); ++i){
			if(i > 0)System.out.print(", ");
			System.out.print(get(i));
		}
		System.out.println("}");
	}
	
	public static void main(String[] args){
		LinkedList<Integer> q = new LinkedList<Integer>();
		for(int i = 0; i < 20; ++i){
			q.enqueue((int)(100*Math.random()));
		}
		q.print();
//		for(int i = 0; i < 10; ++i){
//			q.doTheTerribleThreadingThing();
//		}
		Thread[] t = new Thread[10];
		for(int i = 0; i < t.length; ++i){
			t[i] = new Thread(q);
		}
		for(int i = 0; i < t.length; ++i){
			t[i].start();
		}
		try{Thread.sleep(1000);}catch(Exception e){}
		q.print();
	}
}
